/*
 * Copyright 2021 Huawei Technologies Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
 * in compliance with the License. You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the License
 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
 * or implied. See the License for the specific language governing permissions and limitations under
 * the License.
 */

package org.edgegallery.developer.service.apppackage.csar.appdconverter;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import org.edgegallery.developer.model.application.container.ContainerApplication;
import org.edgegallery.developer.model.apppackage.ImageDesc;
import org.edgegallery.developer.model.apppackage.appd.NodeTemplate;
import org.edgegallery.developer.model.apppackage.appd.TopologyTemplate;
import org.edgegallery.developer.model.apppackage.appd.groups.PlacementGroup;
import org.edgegallery.developer.model.apppackage.appd.policies.AntiAffinityRule;
import org.edgegallery.developer.model.apppackage.appd.vdu.SwImageData;
import org.edgegallery.developer.model.apppackage.appd.vdu.VDUCapability;
import org.edgegallery.developer.model.apppackage.appd.vdu.VDUProperty;
import org.edgegallery.developer.model.apppackage.constant.AppdConstants;
import org.edgegallery.developer.model.apppackage.constant.NodeTypeConstant;

public class ContainerAppTopologyTemplateConverter extends TopologyTemplateConverter {

    public ContainerAppTopologyTemplateConverter() {
        topologyTemplate = new TopologyTemplate();
    }

    /**
     * constructor.
     *
     * @param application application
     * @param imageDescList imageDescList
     * @return
     */
    public TopologyTemplate convertNodeTemplates(ContainerApplication application, List<ImageDesc> imageDescList) {
        updateVnfNode(application.getName(), application.getProvider(), application.getVersion());
        updateVdus(application, imageDescList);
        updateAppConfiguration(application);
        updateGroupsAndPolicies();
        return this.topologyTemplate;
    }

    protected void updateVdus(ContainerApplication application, List<ImageDesc> imageDescList) {
        NodeTemplate vduNode = new NodeTemplate();
        vduNode.setType(NodeTypeConstant.NODE_TYPE_VDU);
        VDUCapability capability = new VDUCapability(4 * AppdConstants.MEMORY_SIZE_UNIT, 4,
            application.getArchitecture(), 20);
        vduNode.setCapabilities(capability);

        StringBuilder imageData = new StringBuilder();
        imageDescList.stream().forEach(image -> imageData.append(image.getName() + ":" + image.getVersion() + ", "));
        VDUProperty propertyContainer = new VDUProperty();
        propertyContainer.getVduProfile().setMaxNumberOfInstances(2);
        propertyContainer.setSwImageData(new SwImageData(imageData.substring(0, imageData.length() - 2)));
        vduNode.setProperties(propertyContainer);

        topologyTemplate.getNodeTemplates().put("logic0", vduNode);
    }

    private void updateGroupsAndPolicies() {
        //update groups
        if (null == topologyTemplate.getGroups()) {
            topologyTemplate.setGroups(new LinkedHashMap<>());
        }
        PlacementGroup group = new PlacementGroup();
        List<String> members = new ArrayList<>();
        for (Map.Entry<String, NodeTemplate> entry : topologyTemplate.getNodeTemplates().entrySet()) {
            if (entry.getValue().getType().equals(NodeTypeConstant.NODE_TYPE_VDU)) {
                members.add(entry.getKey());
            }
        }
        group.setMembers(members);
        topologyTemplate.getGroups().put(AppdConstants.GROUPS_NODE_NAME, group);
        // update policies
        if (null == topologyTemplate.getPolicies()) {
            topologyTemplate.setPolicies(new ArrayList<>());
        }
        LinkedHashMap<String, AntiAffinityRule> policyMap = new LinkedHashMap<>();
        AntiAffinityRule rule = new AntiAffinityRule();
        List<String> groupLst = new ArrayList<>();
        groupLst.add(AppdConstants.GROUPS_NODE_NAME);
        rule.setTargets(groupLst);
        policyMap.put(AppdConstants.POLICY_NODE_NAME, rule);
        topologyTemplate.getPolicies().add(policyMap);

    }
}
